home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 07 - 1991 / 07.02 Feb 91 / 4th Debugger Appl / Calendar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  16.1 KB  |  444 lines  |  [TEXT/KAHL]

  1. /************************************************************************/
  2. /*                                                                          */
  3. /*    Source   - Calendar.c                                                */
  4. /*    Author   - Alexander S. Colwell, Copyright © 1990                    */
  5. /*                                                                        */
  6. /*    Purpose     - This is external area to display an calendar.            */
  7. /*                                                                        */
  8. /*    Notes     - The text strings must be drawn before line separatars,    */
  9. /*               because 4th Dimension has patched the "DrawString" and    */
  10. /*               "DrawChar" in a way that it erases additional pixels        */
  11. /*               above the characters. This problem does not occurs in the*/
  12. /*               "4th Debugger".                                            */
  13. /*                                                                        */
  14. /************************************************************************/
  15.  
  16. #include "Calendar.h"                /* Calendar defs                    */
  17.     
  18. C4th    *New(void) { return(new(CCalendar)); }/*Calendar obj allocator    */
  19.  
  20. void    CCalendar::IExtArea(short getKeyBoard)
  21.     {
  22.         Rect    wRect;                /* Working rect area                */
  23.         
  24.         inherited::IExtArea(TRUE);    /* Do other initialization            */
  25.         
  26.         month = 1;                    /* Set "January" default            */
  27.         year = 1990;                /* Set 1990 year default            */
  28.         daySelect = 0L;                /* Set no selected days                */
  29.         dayIndex = GetDayIndex();    /* Set "day" offset                    */
  30.  
  31.         nextMonth = NewRgn();        /* Allocate next button region        */
  32.         prevMonth = NewRgn();        /* Allocate previous button region    */
  33.     }
  34.     
  35. void    CCalendar::Close(void)
  36.     {
  37.         if (nextMonth)                /* Check if region handle is valid    */
  38.             DisposeRgn(nextMonth);    /* Release this region handle        */
  39.         nextMonth = NULL;            /* Invalidate the region handle        */
  40.         
  41.         if (prevMonth)                /* Check if region handle is valid    */
  42.             DisposeRgn(prevMonth);/* Release this region handle            */
  43.         prevMonth = NULL;            /* Invalidate the region handle        */
  44.         
  45.         inherited::Close();            /* Continue closing                    */
  46.     }
  47.     
  48. void    CCalendar::Cursor(Point pt)    /* Cursor over external area method    */
  49.     {
  50.         register short    i;            /* Working index                    */
  51.         register short    days;        /* Working number of days per month    */
  52.         register short    doIt = FALSE;/* Working status indicator        */
  53.         Rect            wRect;        /* Working day area                    */
  54.         
  55.         if (nextMonth)                /* Check if "next" button region valid*/
  56.             if (PtInRgn(pt,nextMonth))/* Check if inside this region    */
  57.                 doIt = TRUE;        /* Let's do it                        */
  58.             
  59.         if (!doIt)                    /* Check if should continue            */    
  60.             if (prevMonth)            /* Check if "prev" button region valid*/
  61.                 if (PtInRgn(pt,prevMonth))/* Check if inside this region*/
  62.                     doIt = TRUE;    /* Let's do it                        */
  63.                 
  64.         if (!doIt) {                /* Check if should continue            */
  65.             days = GetDays();        /* Get number of days for this month*/
  66.             for(i = 1; i <= days; i++) {/* Search for selected day        */
  67.                 DayRect(&wRect,GetRowIndex(i),GetColumnIndex(i));
  68.                 if (PtInRect(pt,&wRect)) {/* Check if point inside day    */
  69.                     doIt = TRUE;    /* Let's do it                        */
  70.                     break;            /* Break-out of da loop!            */
  71.                 }
  72.             }
  73.         }
  74.  
  75.         if (doIt)                    /* Check if want to do it            */
  76.             inherited::Cursor(pt);    /* OK, let do standard cursor        */
  77.         else                        /* Nope, let's not do it            */
  78.             InitCursor();            /* Reset to arrow cursor            */
  79.     }
  80.     
  81. void    CCalendar::SetupValues(void)
  82.     {
  83.         dayWidth = width / 7;        /* Compute aveage day width            */
  84.         dayHeight = (height - headerHeight) / 7;/* Compute ave day height*/
  85.     }
  86.     
  87. void    CCalendar::Draw(void)
  88.     {
  89.         register short    i;            /* Working index                    */
  90.         register short    days;        /* Working number of days per month    */
  91.         register short    usingColor;    /* Working using color indicator    */
  92.         Str255            label;        /* Working label string                */
  93.         Rect            wRect;        /* Working rect area                */
  94.         RGBColor        saveColor;    /* Working save fore-ground color    */
  95.         register RgnHandle wRgn;    /* Working region handle            */
  96.             
  97.         TextFont(geneva);            /* Set to "Geneva" font                */
  98.         TextSize(9);                /* Set to 9-point font                */
  99.         TextFace(0);                /* Set to "plain" text                */
  100.         
  101.         wRect = drawArea;            /* Setup drawing area                */
  102.         
  103.         EraseRect(&wRect);            /* Clear-out old stuff                */
  104.         FrameRect(&wRect);            /* Frame da calendar                */
  105.         
  106.         SetupValues();                /* Setup working values                */
  107.         
  108.         switch(month) {                /* Copy month to label                */
  109.             case 1:  BlockMove("\pJanuary ",label,9L); break;
  110.             case 2:  BlockMove("\pFeburary ",label,10L); break;
  111.             case 3:  BlockMove("\pMarch ",label,7L); break;
  112.             case 4:  BlockMove("\pApril ",label,7L); break;
  113.             case 5:  BlockMove("\pMay ",label,5L); break;
  114.             case 6:  BlockMove("\pJune ",label,6L); break;
  115.             case 7:  BlockMove("\pJuly ",label,6L); break;
  116.             case 8:  BlockMove("\pAugust ",label,8L); break;
  117.             case 9:  BlockMove("\pSeptember ",label,11L); break;
  118.             case 10: BlockMove("\pOctober ",label,9L); break;
  119.             case 11: BlockMove("\pNovember ",label,10L); break;
  120.             case 12: BlockMove("\pDecember ",label,10L); break;
  121.         }
  122.         
  123.                                     /* Concat year                        */
  124.         NumToString((long)(year),&label[128]);
  125.         BlockMove(&label[129],&label[label[0]+1],(long)(label[128]));
  126.         label[0] += label[128];
  127.         
  128.         DrawDay((char *)(label),0,4);/* Draw Month/Year label            */
  129.         
  130.         DrawDay("\pS",1,1);            /* Draw "Week Day" labels            */
  131.         DrawDay("\pM",1,2);
  132.         DrawDay("\pT",1,3);
  133.         DrawDay("\pW",1,4);
  134.         DrawDay("\pT",1,5);
  135.         DrawDay("\pF",1,6);
  136.         DrawDay("\pS",1,7);
  137.         
  138.         days = GetDays();            /* Get number of days for this month*/
  139.         for(i = 1; i <= days; i++) {/* Draw "Day" labels                */
  140.             NumToString((long)(i),label);
  141.             DrawDay((char *)(label),GetRowIndex(i),GetColumnIndex(i));
  142.         }
  143.             
  144.         if (active || !tmpRgn) {    /* Check if field is active            */
  145.             for(i = 1; i <= days; i++)/* Hilite the days                */
  146.                 if (daySelect & (1L << (long)(i - 0)))
  147.                     HiliteDay(GetRowIndex(i),GetColumnIndex(i));
  148.         }
  149.         else {                        /* Nope, let's frame it                */
  150.             MakeDayOutline();        /* Make day's outline                */
  151.             if (wRgn = NewRgn()) {    /* Check if got region handle        */
  152.                 CopyRgn(tmpRgn,wRgn);/* Copy the outline region handle    */
  153.                 InsetRgn(wRgn,1,1);    /* Shrink it a bit                    */
  154.                 DiffRgn(tmpRgn,wRgn,tmpRgn);/* OK, let's get difference    */
  155.                 DisposeRgn(wRgn);    /* Release working region            */
  156.                 HiliteMode &= 0x7f;    /* Set highliting bit                */
  157.                 InvertRgn(tmpRgn);    /* Outline the days by inverting    */
  158.             }
  159.             else {                    /* Nope, do it less sub-optimal way    */
  160.                 if (usingColor = UsingColor()) {/* Check if using color    */
  161.                     GetForeColor(&saveColor);/* Save fore-ground color    */
  162.                     RGBForeColor(&HiliteRGB);/* Set hilite's fore color    */
  163.                 }
  164.                 FrameRgn(tmpRgn);    /* Outline the days                    */
  165.                 if (usingColor)        /* Check if using color                */
  166.                     RGBForeColor(&saveColor);/* Restore fore color        */
  167.             }
  168.         }
  169.         
  170.                                     /* Draw separators                    */
  171.         MoveTo(drawArea.left,drawArea.top + headerHeight);
  172.         LineTo(drawArea.left + width,drawArea.top + headerHeight);
  173.         MoveTo(drawArea.left,drawArea.top + dayHeight + headerHeight);
  174.         LineTo(drawArea.left + width,drawArea.top + dayHeight + headerHeight);
  175.         
  176.         if (prevMonth) {            /* Check if region handle is valid    */
  177.             if (EmptyRgn(prevMonth)) {/* Check if empty to be drawn        */
  178.                 OpenRgn();            /* Start button drawing                */
  179.                 MoveTo(drawArea.left+3,drawArea.top+headerHeight/2+1);
  180.                 LineTo(drawArea.left+headerHeight/2+2,drawArea.top+1);
  181.                 LineTo(drawArea.left+headerHeight/2+2,drawArea.top+headerHeight/4+1);
  182.                 LineTo(drawArea.left+headerHeight-headerHeight/6,
  183.                        drawArea.top+headerHeight/4+1);
  184.                 LineTo(drawArea.left+headerHeight-headerHeight/6,
  185.                        drawArea.top+headerHeight-headerHeight/4);
  186.                 LineTo(drawArea.left+headerHeight/2+2,
  187.                        drawArea.top+headerHeight-headerHeight/4);
  188.                 LineTo(drawArea.left+headerHeight/2+2,drawArea.top+headerHeight-1);
  189.                 LineTo(drawArea.left+3,drawArea.top+headerHeight/2+1);
  190.                 CloseRgn(prevMonth);/* Close button drawing                */
  191.             }
  192.             if (layout || active)    /* Check if should draw button        */
  193.                 FrameRgn(prevMonth);/* Draw "previous" button            */
  194.         }
  195.         
  196.         if (nextMonth) {            /* Check if region handle is valid    */
  197.             if (EmptyRgn(nextMonth)) {/* Check if empty to be drawn        */
  198.                 OpenRgn();            /* Start button drawing                */
  199.                 MoveTo(drawArea.right-3,drawArea.top+headerHeight/2+1);
  200.                 LineTo(drawArea.right-headerHeight/2-2,drawArea.top+2);
  201.                 LineTo(drawArea.right-headerHeight/2-2,drawArea.top+headerHeight/4+1);
  202.                 LineTo(drawArea.right-headerHeight+headerHeight/6,
  203.                        drawArea.top+headerHeight/4+1);
  204.                 LineTo(drawArea.right-headerHeight+headerHeight/6,
  205.                        drawArea.top+headerHeight-headerHeight/4);
  206.                 LineTo(drawArea.right-headerHeight/2-2,
  207.                        drawArea.top+headerHeight-headerHeight/4);
  208.                 LineTo(drawArea.right-headerHeight/2-2,drawArea.top+headerHeight-1);
  209.                 LineTo(drawArea.right-3,drawArea.top+headerHeight/2+1);
  210.                 CloseRgn(nextMonth);/* Close button drawing                */
  211.             }
  212.             if (layout || active)    /* Check if should draw button        */
  213.                 FrameRgn(nextMonth);/* Draw "next" button                */
  214.         }
  215.     }
  216.     
  217. void    CCalendar::DrawDay(char *label, short row, short column)
  218.     {
  219.         FontInfo    fontInfo;        /* Working font information            */
  220.         Rect        wRect;            /* Working rect area                */
  221.         
  222.         DayRect(&wRect,row,column);    /* Get day rect area                */
  223.         
  224.         GetFontInfo(&fontInfo);        /* Get current font information        */
  225.         
  226.                                     /* Position da string                */
  227.         MoveTo(wRect.left + dayWidth / 2 -  StringWidth(label) / 2,
  228.                wRect.top + ((row ? dayHeight : headerHeight) - 
  229.                     fontInfo.ascent - fontInfo.descent) / 2 + fontInfo.ascent);    
  230.                        
  231.         DrawString(label);            /* Draw the string label            */
  232.     }
  233.     
  234. void    CCalendar::HiliteDay(short row, short column)
  235.     {
  236.         Rect    wRect;                /* Working rect area                */
  237.         
  238.         DayRect(&wRect,row,column);    /* Get day rect area                */
  239.         HiliteMode &= 0x7f;            /* Set highliting bit                */
  240.         InvertRect(&wRect);            /* Invert it                        */
  241.     }
  242.     
  243. void    CCalendar::DayRect(Rect *rect, short row, short column)
  244.     {
  245.         rect->left = rect->top = 0;    /* Set relative day rect area        */
  246.         rect->right = dayWidth;
  247.         rect->bottom = dayHeight;
  248.         
  249.                                     /* Offset the day for drawing        */
  250.         OffsetRect(rect,dayWidth * (column - 1) + drawArea.left,
  251.                    dayHeight * row + 
  252.                    (row ? max(0,headerHeight - dayHeight) : 0) +
  253.                    drawArea.top);
  254.     }
  255.     
  256. short    CCalendar::MakeDayOutline(void)
  257.     {
  258.         register short    i;            /* Working index                    */
  259.         register short    days;        /* Working number of days per month    */
  260.         Rect            wRect;        /* Working rect area                */
  261.         register short    status = FALSE;/* Working status indicator        */
  262.         
  263.         if (tmpRgn) {                /* Check if it's valid                */
  264.             days = GetDays();        /* Get number of days for this month*/
  265.             EmptyRgn(tmpRgn);        /* Set region empty for day framing    */
  266.             OpenRgn();                /* Start region drawing                */
  267.             for(i = 1; i <= days; i++)/* Outline the days                */
  268.                 if (daySelect & (1L << (long)(i - 0))) {/* Selected day?*/
  269.                     status = TRUE;    /* Mark days has some outlining        */
  270.                     DayRect(&wRect,GetRowIndex(i),GetColumnIndex(i));
  271.                     FrameRect(&wRect);
  272.                 }
  273.             CloseRgn(tmpRgn);        /* Copy da region                    */
  274.         }
  275.         
  276.         return(status);                /* Return any days for outlining    */
  277.     }
  278.  
  279. void    CCalendar::Select(void)
  280.     {
  281.         inherited::Select();        /* Do other stuff first                */
  282.         if (MakeDayOutline()) {        /* Make day's outline                */
  283.             InsetRgn(tmpRgn,1,1);    /* Shrink it a bit                    */
  284.             HiliteMode &= 0x7f;        /* Set highliting bit                */
  285.             InvertRgn(tmpRgn);        /* Invert region                    */
  286.         }
  287.         if (nextMonth)                /* Check if has "next" month button    */
  288.             InvalRgn(nextMonth);    /* Invalidate it                    */
  289.         if (prevMonth)                /* Check if has "prev" month button    */
  290.             InvalRgn(prevMonth);    /* Invalidate it                    */
  291.     }
  292.     
  293. void    CCalendar::Deselect(void)
  294.     {
  295.         inherited::Deselect();        /* Do other stuff first                */
  296.         if (MakeDayOutline()) {        /* Make day's outline                */
  297.             InsetRgn(tmpRgn,1,1);    /* Shrink it a bit                    */
  298.             HiliteMode &= 0x7f;        /* Set highliting bit                */
  299.             InvertRgn(tmpRgn);        /* Invert region                    */
  300.         }
  301.         if (nextMonth)                /* Check if has "next" month button    */
  302.             InvalRgn(nextMonth);    /* Invalidate it                    */
  303.         if (prevMonth)                /* Check if has "prev" month button    */
  304.             InvalRgn(prevMonth);    /* Invalidate it                    */
  305.     }
  306.     
  307. void    CCalendar::Scroll(void)
  308.     {
  309.         if (nextMonth)                /* Check if got "next" region handle*/
  310.             OffsetRgn(nextMonth,drawArea.left - prevArea.left,
  311.                                 drawArea.top - prevArea.top);
  312.                                 
  313.         if (prevMonth)                /* Check if got "prev" region handle*/
  314.             OffsetRgn(prevMonth,drawArea.left - prevArea.left,
  315.                                 drawArea.top - prevArea.top);
  316.     }
  317.     
  318. void    CCalendar::DoClick(Point pt, short modifiers, long ticks)
  319.     {
  320.         register short    i;            /* Working index                    */
  321.         register short    lastDay = 0;/* Working last day selected        */ 
  322.         register short    days;        /* Working number of days per month    */
  323.         register short    hiliteMode = TRUE;/* Working hilite mode        */
  324.         register unsigned long    mask;/* Working mask                    */
  325.         short            row;        /* Working row day position            */
  326.         short            column;        /* Working column day position        */
  327.         Rect            wRect;        /* Working rect area                */
  328.  
  329.         if (nextMonth) {            /* Check if selecting "next" month    */
  330.             if (TrackMouse(pt,nextMonth)) {/* Track da mouse!!            */
  331.                 daySelect = 0L;        /* Zap current selection            */
  332.                 month += 1;            /* Go to next month                    */
  333.                 if (month == 13) {    /* Check if it's into next year        */
  334.                     month = 1;        /* Reset to "January"                */
  335.                     year += 1;        /* Re-draw the calendar                */
  336.                 }
  337.                 dayIndex = GetDayIndex();/* Set "day" offset            */
  338.                 Draw();                /* Re-draw the calendar                */
  339.             }
  340.         }
  341.         
  342.         if (prevMonth) {            /* Check if selecting "previous" month*/
  343.             if (TrackMouse(pt,prevMonth)) {/* Still selecting?            */
  344.                 daySelect = 0L;        /* Zap current selection            */
  345.                 month -= 1;            /* Go to previous month                */
  346.                 if (month == 0) {    /* Check if it's into previous year    */
  347.                     month = 12;        /* Reset to "Decemeber"                */
  348.                     year -= 1;        /* Go to previous year                */
  349.                 }
  350.                 dayIndex = GetDayIndex();/* Set "day" offset            */
  351.                 Draw();                /* Re-draw the calendar                */
  352.             }
  353.         }
  354.  
  355.         days = GetDays();            /* Get number of days for this month*/
  356.             
  357.         do {                        /* Track da mouse!!                    */
  358.             for(i = 1; i <= days; i++) {/* Search for selected day        */
  359.                 DayRect(&wRect,row = GetRowIndex(i),
  360.                                 column = GetColumnIndex(i));
  361.                 if (PtInRect(pt,&wRect)) {/* Check if point inside day    */
  362.                     mask = (1L << (long)(i - 0));/* Set mask            */
  363.                     if (!lastDay) {    /* Check if first time                */
  364.                         if (daySelect & mask)/* Check if hilited        */
  365.                             hiliteMode = FALSE;/* Reset to hiliting mode*/
  366.                     }
  367.                     if (lastDay != i) {/* Check if it's new day            */
  368.                         if (hiliteMode) {/* Check if hiliting the days    */
  369.                             if (!(daySelect & mask)) {/* Not selected ?    */
  370.                                 HiliteDay(row,column);/* Hilite day        */
  371.                                 daySelect ^= mask;/* Set this day        */
  372.                             }
  373.                         }
  374.                         else {        /* Nope, unhiliting the days        */
  375.                             if (daySelect & mask) {/* Selected ?        */
  376.                                 HiliteDay(row,column);/* Unhilite day    */
  377.                                 daySelect ^= mask;/* Clear this day        */
  378.                             }
  379.                         }
  380.                     }
  381.                     lastDay = i;    /* Save last selected day            */
  382.                 }
  383.             }
  384.             GetMouse(&pt);            /* Get next mouse position            */
  385.         } while(Button());            /* Track while mouse is down        */
  386.     }
  387.     
  388. short    CCalendar::GetDays(void)
  389.     {
  390.         register short    days;        /* Working number of days            */
  391.         static short     monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
  392.         
  393.         if ((days = monthDays[month - 1]) == 28)/* Check if "Feburary"    */
  394.             days += LeapYear();        /* Add leap year day                */
  395.             
  396.         return(days);                /* Return number of days            */
  397.     }
  398.     
  399. short    CCalendar::GetDayIndex(void)
  400.     {
  401.         DateTimeRec    dateTime;        /* Working date/time stamp            */
  402.         long        secs;            /* Working seconds                    */
  403.         
  404.         dateTime.year = year;        /* Init date/time stamp                */
  405.         dateTime.month = month;
  406.         dateTime.day = 1;
  407.         dateTime.hour = 0;
  408.         dateTime.minute = 0;
  409.         dateTime.second = 0;
  410.         
  411.         Date2Secs(&dateTime,&secs);    /* Translate to seconds                */
  412.         Secs2Date(secs,&dateTime);    /* Convert it back to get day of week*/
  413.         
  414.         return(dateTime.dayOfWeek - 1);/* Return day of the week        */
  415.     }
  416.     
  417. short    CCalendar::GetRowIndex(short idx)
  418.     {    return(2 + ((idx - 1 + dayIndex) / 7)); }
  419.     
  420. short    CCalendar::GetColumnIndex(short idx)
  421.     {    return(1 + ((idx - 1 + dayIndex) % 7)); }
  422.     
  423. short    CCalendar::LeapYear(void)
  424.     {
  425.         DateTimeRec        dateTime;    /* Working date/time stamp            */
  426.         long            secs;        /* Working seconds                    */
  427.         register short    leapDay = 0;/* Working leap year day            */
  428.         
  429.         dateTime.year = year;        /* Init date/time stamp                */
  430.         dateTime.month = month;
  431.         dateTime.day = 29;
  432.         dateTime.hour = 0;
  433.         dateTime.minute = 0;
  434.         dateTime.second = 0;
  435.         
  436.         Date2Secs(&dateTime,&secs);    /* Translate to seconds                */
  437.         Secs2Date(secs,&dateTime);    /* Convert it back to get day of week*/
  438.         
  439.         if (dateTime.day == 29)        /* Check if it's still same day        */
  440.             leapDay = 1;            /* Yup, it's leap year!!!!            */
  441.             
  442.         return(leapDay);            /* Return leap year day                */
  443.     }
  444.